import { Inject, Provide } from '@midwayjs/decorator';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm'
import { Context } from '@midwayjs/koa'
import { JwtService } from '@midwayjs/jwt';
import axios from 'axios'
import pri from '../privacy'
import { UserEntity } from '../entity/user';
import { RedisService } from '@midwayjs/redis';
import WXBizDataCrypt from '../utils/WXBizDataCrypt';
import * as md5 from 'md5'
import { GroupEntity } from '../entity/group';
import privacy from '../privacy';
const fs = require('fs')
const path = require('path')
var crypto = require("crypto");
// import sha256 from 'crypto-js';
// import WxPay from 'wechatpay-node-v3'
// const  WxPay =require('wechatpay-node-v3')
var parseString = require('xml2js').parseString;
/**
 * 描述
 */
@Provide()
export class WxService {

  @Inject()
  ctx: Context;

  @InjectEntityModel(UserEntity)
  UserModel: Repository<UserEntity>

  @InjectEntityModel(GroupEntity)
  groupModel: Repository<GroupEntity>;

  @Inject()
  redisService: RedisService;

  @Inject()
  jwtService: JwtService;


  /**
   * 描述
   */
  async login(body) {
    console.log("请求");
    console.log(body.code);
    console.log(pri.appid);
    console.log(pri.appSecret);
    var data = {
      appid: pri.appid,
      secret: pri.appSecret,
      js_code: body.code,
      grant_type: "authorization_code"
    }
    let result = await axios({
      url: 'https://api.weixin.qq.com/sns/jscode2session',
      params: data
    })

    /* 
         得到openid 之后我们要做什么? 
         1.先检验有没有该用户 , 有的话直接返回 token 
         2.没有注册并返回token
    */
    // let find   = await this.UserModel.find({ where:{  openid: result.data.code  } })

 
    let find = await this.UserModel.createQueryBuilder('user').where('user.openid = :id', { id: result.data.openid }).getOne()
    console.log("find", find);
   
    if (find != null) {
      let token =   this.jwtService.signSync({...find})
      return {
        code: "20000",
        token: token,
        userinfo: find
      }
    } else {
      var obj = new UserEntity
      obj.openid = result.data.openid
      obj.session_key = result.data.session_key
      obj.avatar ="https://rd5-public.zhaopin.cn/imgs/staff/d1015c3b944d72fdb70a24650d6b7d73.jpg?x-oss-process=image/crop,x_14,y_0,w_619,h_619"
      //  要对账号进行注册
      obj.name = "默认用户"
      let userinfo = await this.UserModel.save(obj)
    
      return {
        code: "20001",
        token:   this.jwtService.signSync(userinfo),
        userinfo: userinfo
      }

    }



  }


  async loginH5(body){
    console.log(body.tell);
    console.log(body.password );
    let find = await this.UserModel.createQueryBuilder('user').where('user.phone = :id', { id: body.tell }).getOne()
    console.log("find", find);
    if (find != null) {
      let token =   this.jwtService.signSync({...find})
      
      return {
        code: "20000",
        token: token,
        userinfo: find
      }
    } else {
      var obj = new UserEntity
      obj.phone = body.tell
      obj.password = body.password
      //  要对账号进行注册
         
      let userinfo = await this.UserModel.save(obj)
    
      return {
        code: "20000",
        token:   this.jwtService.signSync(find),
        userinfo: userinfo
      }
  }
}


  async getiphone(body) {
    console.log("请求");
    console.log(body.code);
    let access_token = await this.redisService.get('access_token')
    
    let { data } = await axios({
      url: "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + access_token,
      method: "post",
      data: {
        code: body.code
      }
    })
     let { id } = await this.getuserinfo()
     console.log("用户id",id);
     console.log(data);
    await this.UserModel.createQueryBuilder().update().set({ phone:data.phone_info.phoneNumber}).where( "id=:id",{id}).execute()

    return {
      code: 20000,
      data: data
    }
  }
  async getiphonev2(body) {
    console.log("请求");
    console.log(body.encryptedData);
    console.log(body.iv);
    // V2 vi  data  还要携带token
    // axios 请求拦截器
    // 拿之前 设置token的代码来 
    //  查询用户的信息
    //  读取用户的 信息

    let wx = new WXBizDataCrypt(pri.appid, 'ebAQhc4TG6Z7Yi5o8JyuXw==')
    console.log("wx", wx);

    let result = wx.decryptData(body.encryptedData, body.iv)
    console.log("result", result);

    return {
      code: 20000,
      msg: "成功"
    }


  }


  async addUser(userData: Partial<UserEntity>) {
    const newUser = await this.UserModel.save(this.UserModel.create(userData));
    return newUser;
  }

  async removeUser(userId: number) {
    const result = await this.UserModel.delete(userId);
    return result;
  }


  async createGroup(groupData: Partial<GroupEntity>) {
    const newGroup = await this.groupModel.save(this.groupModel.create(groupData));
    return newGroup;
  }

  async joinGroup(groupId: number, userId: number) {
    const group = await this.groupModel.findOne({ where: { id: groupId }, relations: ['members'] });
    const user = await this.UserModel.findOne({ where: { id: userId } });

    if (group && user) {
      group.members.push(user);
      await this.groupModel.save(group);
      return group;
    }

    return null;
  }

  async leaveGroup(groupId: number, userId: number) {
    const group = await this.groupModel.findOne({ where: { id: groupId }, relations: ['members'] });
    const userIndex = group?.members.findIndex(member => member.id === userId);

    if (group && userIndex !== -1 && userIndex !== undefined) {
      group.members.splice(userIndex, 1);
      await this.groupModel.save(group);
      return group;
    }

    return null;
  }

  /**
   * 获取用户信息  解析token 获得用户头像
   */
  async getuserinfo() {
    //  解析token  返回用户信息
    let result: any = {}

    let token = this.ctx.request.header.token || this.ctx.request.header.authorization.split(" ")[1]
    console.log("token",token);
    
    result = this.jwtService.verifySync(token + "", { complete: true })
    console.log("解析结果", result);
    
    return result.payload
  }


  async pay(body) {
    console.log(body);




    var payData = {
      openid: 'o01r05CtNMAI4RxsY4FHu454xpWg',
      appid: pri.appid,
      mch_id: pri.mch_id,
      nonce_str: await this.getNonceStr(32),
      // body: "支付"+result.orderItemlist[0].title ,
      body: "支付",
      out_trade_no: this.createOrderSn(3),
      total_fee: 10,
      notify_url: "https://zlwh.jinghuanqiu.com/wx/wxnotify", // 异步通知地址,需要线上域名地址，本地ip不行
      trade_type: 'JSAPI'

    }
    let sign = await this.createSign(payData);
    var formData = `<xml>
<appid>${payData.appid}</appid>
<body>${payData.body}</body>
<mch_id>${payData.mch_id}</mch_id>
<nonce_str>${payData.nonce_str}</nonce_str>
<notify_url>${payData.notify_url}</notify_url>
<openid>${payData.openid}</openid>
<out_trade_no>${payData.out_trade_no}</out_trade_no>
<total_fee>${payData.total_fee}</total_fee>
<trade_type>${payData.trade_type}</trade_type>
<sign>${sign}</sign>
</xml>`;
    // 发送给微信的接口   
    var url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'
    let { data: result } = await axios({
      url,
      method: "post",
      data: formData,

    })
    console.log(result);

    var result2: any = {}
    parseString(result, async (err, xml) => {

      xml = xml.xml
      xml.package = "prepay_id=" + xml.prepay_id
      xml.timeStamp = parseInt((Date.now() / 1000) + "")

      result2 = {
        appid: xml.appid[0],
        timeStamp: xml.timeStamp,
        nonceStr: xml.nonce_str[0],
        package: xml.package,
      }
      let paramStr = `appId=${xml.appid[0]}&nonceStr=${xml.nonce_str[0]}&package=${result2.package}&signType=MD5&timeStamp=${xml.timeStamp}&key=${pri.pay_api_key}`
      let paySign = md5(paramStr).toUpperCase();
      // var paySign = await this.createSign(result2)
      // console.log("签名",paySign);

      result2.paySign = paySign
      result2.signType = "MD5"
      console.log(result2);
    })
    return {
      code: 20000,
      data: result2
    }

  }



  async payv2() {

    var payData = {
      openid: 'o01r05CtNMAI4RxsY4FHu454xpWg',
      appid: pri.appid,
      mch_id: pri.mch_id,
      nonce_str: await this.getNonceStr(32),
      // body: "支付"+result.orderItemlist[0].title ,
      body: "支付",
      out_trade_no: this.createOrderSn(3),
      total_fee: 10,
      notify_url: "https://zlwh.jinghuanqiu.com/wx/wxnotify", // 异步通知地址,需要线上域名地址，本地ip不行
      trade_type: 'JSAPI'

    }
    //  需要转化为xml格式 
    let sign = await this.createSign(payData);
    var formData = `<xml>
<appid>${payData.appid}</appid>
<body>${payData.body}</body>
<mch_id>${payData.mch_id}</mch_id>
<nonce_str>${payData.nonce_str}</nonce_str>
<notify_url>${payData.notify_url}</notify_url>
<openid>${payData.openid}</openid>
<out_trade_no>${payData.out_trade_no}</out_trade_no>
<total_fee>${payData.total_fee}</total_fee>
<trade_type>${payData.trade_type}</trade_type>
<sign>${sign}</sign>
</xml>`;

    let result = await axios({
      url: "https://api.mch.weixin.qq.com/pay/unifiedorder",
      method: "post",
      data: formData
    })

    let data = result.data
    console.log(data);

    var result2
    parseString(data, async (err, xml) => {
      result2 = xml.xml
    })
    console.log(result2.prepay_id[0]);




    return {
      code: "20000",
      data: {
        xml: {
          prepay_id: result2.prepay_id[0],
          mch_id: result2.mch_id[0],
          appId: result2.appid[0],
          nonceStr: result2.nonce_str[0],
          pay_api_key: pri.pay_api_key,
          signType: "MD5"
        }
      }
    }



  }

  async payv3() {

    var data = {
      "mchid": pri.mch_id + "",
      "out_trade_no": this.createOrderSn(3) + "",
      "appid": pri.appid + "",
      "description": "Image形象店-深圳腾大-QQ公仔",
      "notify_url": "https://zlwh.jinghuanqiu.com/notify/wxnotify",
      "amount": {
        "total": 1, // 0.01
        "currency": "CNY"
      },
      "payer": {
        "openid": "o01r05CtNMAI4RxsY4FHu454xpWg"
      }
    }
    var timestamp = parseInt((Date.now() / 1000) + "")
    var NonceStr = await this.getNonceStr(32)
    // V3特殊点: 需要带一个 token
    // WECHATPAY2-SHA256-RSA2048 固定写法
    // serial_no 证书编号

    var creatEsingSTR = `POST/v3/pay/transactions/jsapi\n${timestamp}\n${NonceStr}\n${JSON.stringify(data)}\n`
    var signture = crypto.createSign('RSA-SHA256')
    signture.update(creatEsingSTR)
    var sig = await signture.sign(fs.readFileSync(path.resolve(__dirname, "../cert/apiclient_key.pem")), 'base64')
    console.log(sign);

    var str = `WECHATPAY2-SHA256-RSA2048 mchid="${data.mchid}",signature="${sig}",timestamp="${timestamp}",nonce_str="${NonceStr}",serial_no="6F1F858EDC1A300CE2393F69573CEAD26CC3D6A3"`



    let result = await axios({
      url: "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi",
      method: "post",
      data: data,
      headers: {
        "Authorization": str,
        "Content-Type": "application/json",
        "Accept": "application/json"
      }
    })
    console.log("resultV3", result.data);
    var package2 = "prepay_id=" + result.data.prepay_id



    //  发送完毕以后, 要再进行签名加密, 签名加密的方式跟V2的不一样, 所以需要重新再写一个签名加密的方式
    var strsign = `${pri.appid}\n${timestamp}\n${NonceStr}\n${package2}\n`
    //  加密密文



    var sign = await this.createSignv3(strsign)
    return {
      code: 20000,
      data: {
        NonceStr,
        timestamp,
        package: "prepay_id=" + result.data.prepay_id,
        signType: "RSA",
        paySign: sign
      }
    }
    //  改成 函数化实现 支付 
  }


async pay24(){
  //  支付0.01
  // 发送请求 
  let url = "/v3/pay/transactions/jsapi"
  let timestamp  = parseInt(Date.now()/1000+"") 
  let nonce_str = await this.getNonceStr(32)
  let data = {
    appid:privacy.appid+"",
    mchid:privacy.mch_id+"",
    description:"明德前端课程",
    out_trade_no: this.createOrderSn(1)+"",
    notify_url:"https://zlwh.jinghuanqiu.com/wx/wxnotify",
    "amount": {
      "total": 1, // 0.01
      "currency": "CNY"
    },
    "payer": {
      "openid": "o01r05CtNMAI4RxsY4FHu454xpWg"
    }
  }
  let a  = `POST\n${url}\n${timestamp}\n${nonce_str}\n${JSON.stringify(data)}\n`

  var signture = crypto.createSign('RSA-SHA256')
  signture.update(a )
  var sig = await signture.sign(fs.readFileSync(path.resolve(__dirname, "../cert/apiclient_key.pem")), 'base64')

  let Authorization =` WECHATPAY2-SHA256-RSA2048 mchid="${privacy.mch_id}",nonce_str="${nonce_str}",signature="${sig}",timestamp="${timestamp}",serial_no="6F1F858EDC1A300CE2393F69573CEAD26CC3D6A3"` 
 
  let result = await axios({
    method:"post",
    url:"https://api.mch.weixin.qq.com"+url,
    headers:{
      Accept:"application/json",
      "Content-Type":"application/json",
      Authorization
    },
    data
  })
  //  得到payid 
  var package2 = "prepay_id=" + result.data.prepay_id
  var strsign = `${pri.appid}\n${timestamp}\n${nonce_str}\n${package2}\n`
  //  加密密文



  var sign = await this.createSignv3(strsign)
  return { 
    ...result.data,
    timestamp,
    nonce_str,
    package:`prepay_id=${result.data.prepay_id}`,
    signType: "RSA",
    paySign: sign,
    orderSn: data.out_trade_no
  }

}


  async sendmsg() {
    console.log(123);
    // let token = await this.redisService.get('access_token')
    let token = '80_SvOO2zjQRhLjxE46_uWUkLVJ71O-EAZ6UZ7Y0iTN6qhfF4umYovQ1x0ChUa1qcD-zQKEdNXXquw17sPep9ExeJqjkm878NRiGC2oXNEIfQKWkUiPmd2KYUJkxnkYAWcACASUQ'
    console.log(token);


    let result = await axios({
      url: "https://api.weixin.qq.com/cgi-bin/message/subscribe/send",
      params: {
        access_token: token
      },
      method: "post",
      data: {
        touser: "o01r05CtNMAI4RxsY4FHu454xpWg", //openid
        template_id: "1KCVEvdX0YJCsC-deQH9qyUHr4VgcR9SqBDxEGMfCLE",
        
        data: {
          "name1": {
            "value": "小周"
          },
          "phone_number2": {
            "value": "159177888888"
          },
          "time3": {
            "value": "2019年9月21日 21:00:06"
          },
          "thing4": {
            "value": "腾讯科技"
          },
          "thing7": {
            "value": "原子弹"
          }

        },
        miniprogram_state: "developer",
        lang: "zh_CN"
      }


    })
    console.log(result.data);

    return {
      code: 2000,
      msg: "发送成功",
      // data:result
    }

  }

  async send40004() {
    return {
      code: 40004,
      msg: "登录过期"
    }
  }
  createOrderSn(id: number) {
    var timer = new Date()
    return timer.getFullYear() + "" + ((timer.getMonth() + 1).toString().padStart(2, "0")) + timer.getDate() + timer.getMilliseconds().toString().padStart(3, "0") + ((timer.getHours() + 6).toString().padStart(2, "0")) + timer.getSeconds().toString().padStart(2, "0") + timer.getMinutes() + (id + 1234)
  }
  async getNonceStr(len) {
    let str = "0123456789abcdefghijklmnopqrstuvwxyz";
    let newStr = "";
    for (let i = 0; i < len; i++) {
      let index = Math.floor(Math.random() * str.length);
      newStr += str[index];
    }
    return newStr;
  }


  async refunds(orderSn,num){

    let url = "/v3/refund/domestic/refunds"
    let timestamp  = parseInt(Date.now()/1000+"") 
    let nonce_str = await this.getNonceStr(32)
    let data = {
      out_trade_no:orderSn+"",
      out_refund_no:this.createOrderSn(1)+"" ,
      amount: {
        refund: 1, // 0.01
        total: 1,
        currency : "CNY"
      },
    
    }
    console.log("数据",data);
    
    let a  = `POST\n${url}\n${timestamp}\n${nonce_str}\n${JSON.stringify(data)}\n`
    // let a  = `POST\n${url}\n${timestamp}\n${nonce_str}\n`
  
    var signture = crypto.createSign('RSA-SHA256')
    console.log("签名加密信息",a);
    
    signture.update(a )
    var sig = await signture.sign(fs.readFileSync(path.resolve(__dirname, "../cert/apiclient_key.pem")), 'base64')
  
    let Authorization =` WECHATPAY2-SHA256-RSA2048 mchid="${privacy.mch_id}",nonce_str="${nonce_str}",signature="${sig}",timestamp="${timestamp}",serial_no="6F1F858EDC1A300CE2393F69573CEAD26CC3D6A3"` 
   console.log("Authorization",Authorization);
    
    try{
   await axios({
        method:"post",
        url:"https://api.mch.weixin.qq.com"+url,
        headers:{
          Accept: 'application/json',
          'Content-Type': 'application/json',
          Authorization
        },
        data
      })
    }catch{
      
    }
  
   
    return { 
       code:2000,

    }
  }


  async createSign(obj) {
    //签名算法（把所有的非空的参数，按字典顺序ASCILL组合起来+key,然后md5加密，再把加密结果都转成大写的即可）
    //  将对象转化为数组进行排序
    //  将需要加入签名的 参数 放在一个对象 keys转化为一个数组   sort() 默认就是ASCILL 排列方式
    let arr = Object.keys(obj).sort()
    var stra = arr.reduce((v, e) => {
      v = v + e + '=' + obj[e] + "&"
      return v
    }, "")
    //  微信商户得到
    let stringSignTemp = stra + 'key=' + pri.pay_api_key;
    console.log("签名顺序", stringSignTemp);

    //  MD5 加密再转大写
    stringSignTemp = md5(stringSignTemp);
    let signValue = stringSignTemp.toUpperCase();

    return signValue
  }
  async createSignv3(obj) {
    console.log("加密内容", obj);

    var signture = crypto.createSign('RSA-SHA256')
    signture.update(obj)
    var signValue = signture.sign(fs.readFileSync(path.resolve(__dirname, "../cert/apiclient_key.pem")), 'base64')

    return signValue
  }

}

